Option Explicit

' 获取一个只包含一个 token 组合的字符串
Private Const GET_ONE_TOKEN_ARRY_STR As String = "xyz"
' 获取一个 token 组合的字符串
Private Const GET_TOKEN_ARRY_STR As String = "xyz, abc (c1, c2)"

Private Const TEST_TABLE_NAME As String = "table1"
Private Const TEST_POINT As String = "."
Private Const TEST_COL_NAME As String = "col1"
Private Const TEST_SHARE_LINE_COMMENT As String = "--aaaaaa"
Private Const TEST_SINGLE_LINE_COMMENT As String = "--bbbbb"

Private Const TEST_COMMENT_1 As String = "--comment1"
Private Const TEST_COMMENT_2 As String = "--comment2"
Private Const TEST_COMMENT_3 As String = "--comment3"

' ======================================================================
' 执行所有测试用例
' ======================================================================
Public Sub test_all_case()
    ' 测试: 生成两个元素组成的 token组合
    test_createTwoElemTokenGroup

    ' 测试: 生成连续连接的字符串元素
    test_createContinuousStrElem

    ' 测试: 将一个对象包装为连续连接的字符串元素
    test_wrapperElemToContinuousStrElem

    ' 测试: 生成一个逗号分隔的多个元素
    test_createCommaDelimitMultiElem

    ' 测试: 生成一个容器作用域
    test_createContainerEnv

    ' 测试: 生成一个key开始的作用域
    test_createKeyStartEnv

    ' 测试: 生成一个KeySectionEnv
    test_createKeySectionEnv

    ' 测试: 将一个条件包装为多条件组合
    test_wrapToMultiConditions

    ' 测试: 创建一个多条件组合
    test_createMultiConditions

    ' 测试: 生成条件对象
    test_createCondition

    ' 测试: 生成条件对象的条件运算符左侧的内容
    test_createConditionOnlyOpLeft

    ' 测试: 生成一个容器列
    test_createContainerCol

    ' 测试: 将一个作用域包装为容器作用域
    test_wrapperEnvToContainerEnv

    ' 测试: 将一个列包装为容器列
    test_wrapperColToContainerCol

    ' 测试: 将一个列转换为表达式列
    test_transColToExprCol

    ' 测试: 生成一个函数列对象
    test_createFuncCol

    ' 测试: 生成一个case列对象
    test_createCaseCol

    ' 测试: 生成一个case的组成元素
    test_createCaseCompositionElem

    ' 测试: 检查ON起始的作用域是不是ON_DUPLICATE作用域
    test_isOnDuplicateEnv

    ' 测试: 连接组成元素数组为一行字符串
    test_createFormatSingleStr

    ' 测试: 以每个元素独占一行的形式生成字符串集合
    test_createElemExclusiveRowStrArr

    ' 测试: 以每个元素独占一行的形式填充字符串集合
    test_fullElemExclusiveRowStrArr

    ' 测试: 以连续连接元素的方式生成字符串集合
    test_createElemContinuousStrArr

    ' 测试: 以连续连接和逗号换行的方式生成字符串集合
    test_createElemContinuousAndDelimitByCommaStrArr

    ' 测试: 连接对齐元素中的组成元素并填充到结果集合
    test_fullAndJoinArrayElem

    ' 测试: 通用方法--连接两个元素的字符串
    test_joinTwoElemStr

    ' ==================================================
    ' 计算元素的偏移量
    ' ==================================================
    ' 测试: 获取左括号栈中下一个左括号的偏移量
    test_getLeftParenthesisOffsetInStack

    ' 测试: 获取扫描器到下一个最近的逗号的偏移量
    test_getNextCommaOffset

    ' 测试: 获取扫描器到下一个最近的左括号的偏移量
    test_getNextLeftParenthesisOffset

    ' 测试: 获取扫描器到下一个最近的右括号的偏移量
    test_getNextRightParenthesisOffset

    ' 测试: 获取扫描器到下一个最近的目标元素的偏移量
    test_getNextTargetElemOffset

    ' 测试: 获取扫描器到下一个最近的筛选行为关键字的偏移量
    test_getNextSelectStartActionSqlKeyOffset

    ' 测试: 获取扫描器到下一个最近的不是sql各部分的起始关键字的偏移量
    test_getNextNonSectionStartSqlKeyOffset

    ' 测试: 获取扫描器到下一个最近运算符的偏移量
    test_getNextOperatorOffset

    ' 测试: 获取扫描器到下一个最近的算数运算符的偏移量
    test_getNextComputeOperatorOffset

    ' 测试: 获取扫描器到下一个最近的条件运算符的偏移量 (为了兼容条件运算符前的 Not 运算符，这里也检查 Not)
    test_getNextConditionOperatorOffset

    ' 测试: 获取扫描器到下一个最近的不是使匹配筛选项操作停止的sql关键字的偏移量
    test_getNextNonSelectItemStopSqlKeyOffset

    ' 测试: 获取扫描器到下一个最近的表定义的偏移量
    test_getNextTableFactorOffset

    ' 测试: 获取扫描器到下一个最近的index_hint起始关键字的偏移量
    test_getNextIndexHintStartKeyOffset

    ' 测试: 获取扫描器到下一个最近的with表定义的偏移量
    test_getNextWithTableOffset

    ' 测试: 获取扫描器到下一个最近的update行为关键字的偏移量
    test_getNextUpdateStartActionSqlKeyOffset

    ' 测试: 获取扫描器到下一个最近的delete行为关键字的偏移量
    test_getNextDeleteStartActionSqlKeyOffset

    ' 测试: 获取扫描器到下一个最近的insert行为关键字的偏移量
    test_getNextInsertStartActionSqlKeyOffset

    ' 测试: 获取扫描器到下一个rowAlias的偏移量
    test_getNextRowAliasOffset
End Sub

' ======================================================================
' 测试通用方法
' ======================================================================

' 创建一个扫描器
Private Function getObjArrayRefScanner(ParamArray tokens() As Variant) As ObjArrayRefScanner
    Dim i As Integer
    Dim t As SqlToken

    Dim tokenCount As Integer
    tokenCount = UBound(tokens)

    ' 创建一个和参数数量相同的数组引用
    Dim meanTokens As IObjArrayRef
    Set meanTokens = UtilsArrayRef.createRealObjArrayRef(tokenCount)

    ' 遍历参数，并保持到数组引用
    For i = 0 To UBound(tokens)
        Set t = tokens(i)

        meanTokens.Add t
    Next

    ' 创建扫描器
    Dim scanner As ObjArrayRefScanner
    Set scanner = New ObjArrayRefScanner
    scanner.Init meanTokens

    ' return scanner
    Set getObjArrayRefScanner = scanner
End Function

' 获取 LOW_PRIORITY 关键字
Private Function getLowPriorityToken() As SqlToken
    Set getLowPriorityToken = New SqlToken
    getLowPriorityToken.Init "low_priority", SqlTokenType.KEY_LOW_PRIORITY
End Function

' 获取 HIGH_PRIORITY 关键字
Private Function getHighPriorityToken() As SqlToken
    Set getHighPriorityToken = New SqlToken
    getHighPriorityToken.Init "high_priority", SqlTokenType.KEY_HIGH_PRIORITY
End Function

' 获取 not 关键字
Private Function getNotToken() As SqlToken
    Set getNotToken = New SqlToken
    getNotToken.Init "not", SqlTokenType.KEY_NOT
End Function

' 获取 distinct 关键字
Private Function getDistinctToken() As SqlToken
    Set getDistinctToken = New SqlToken
    getDistinctToken.Init "distinct", SqlTokenType.KEY_DISTINCT
End Function

' 生成一个函数名称元素
Private Function createFuncNameToken(ByVal funcName As String) As SqlToken
    Set createFuncNameToken = New SqlToken
    createFuncNameToken.Init funcName, SqlTokenType.STR_FUNC
End Function

' 获取 force 关键字
Private Function getForceToken() As SqlToken
    Set getForceToken = New SqlToken
    getForceToken.Init "force", SqlTokenType.KEY_FORCE
End Function

' 获取 ignore 关键字
Private Function getIgnoreToken() As SqlToken
    Set getIgnoreToken = New SqlToken
    getIgnoreToken.Init "ignore", SqlTokenType.KEY_IGNORE
End Function

' 获取 delayed 关键字
Private Function getDelayedToken() As SqlToken
    Set getDelayedToken = New SqlToken
    getDelayedToken.Init "delayed", SqlTokenType.KEY_DELAYED
End Function

' 获取 quick 关键字
Private Function getQuickToken() As SqlToken
    Set getQuickToken = New SqlToken
    getQuickToken.Init "quick", SqlTokenType.KEY_QUICK
End Function

' 获取 use 关键字
Private Function getUseToken() As SqlToken
    Set getUseToken = New SqlToken
    getUseToken.Init "use", SqlTokenType.KEY_USE
End Function

' 获取 with 关键字
Private Function getWithToken() As SqlToken
    Set getWithToken = New SqlToken
    getWithToken.Init "with", SqlTokenType.KEY_WITH
End Function

' 获取 select 关键字
Private Function getSelectToken() As SqlToken
  Set getSelectToken = New SqlToken
  getSelectToken.Init "select", SqlTokenType.KEY_SELECT
End Function

' + 运算符
Private Function getPlusToken() As SqlToken
  Set getPlusToken = New SqlToken
  getPlusToken.Init "+", SqlTokenType.OPERA_PLUS
End Function

' 获取 union 关键字
Private Function getUnionToken() As SqlToken
    Set getUnionToken = New SqlToken
    getUnionToken.Init "union", SqlTokenType.KEY_UNION
End Function

' on 关键字
Private Function getOnToken() As SqlToken
    Set getOnToken = New SqlToken
    getOnToken.Init "on", SqlTokenType.KEY_ON
End Function

' 获取 duplicate 关键字
Private Function getDuplicateToken() As SqlToken
    Set getDuplicateToken = New SqlToken
    getDuplicateToken.Init "duplicate", SqlTokenType.KEY_DUPLICATE
End Function

' 获取右括号
Private Function getRightParenthesisToken() As SqlToken
    Set getRightParenthesisToken = New SqlToken
    getRightParenthesisToken.Init ")", SqlTokenType.RIGHT_PARENTHESIS
End Function

' 获取左括号
Private Function getLeftParenthesisToken() As SqlToken
    Set getLeftParenthesisToken = New SqlToken
    getLeftParenthesisToken.Init "(", SqlTokenType.LEFT_PARENTHESIS
End Function

' 获取一个单行的注释
Private Function createSingleLineCommentToken(ByRef v As String) As SqlToken
    Set createSingleLineCommentToken = New SqlToken
    createSingleLineCommentToken.Init v, SqlTokenType.SINGLE_LINE_COMMENT
End Function

' 创建和前一个元素在同一行的注释
Private Function createShareLineCommentToken(ByRef v As String) As SqlToken
    Set createShareLineCommentToken = New SqlToken
    createShareLineCommentToken.Init v, SqlTokenType.SHARE_LINE_COMMENT
End Function

' 获取一个条件运算符: <=
Private Function getLeConditionOperator() As SqlToken
    Set getLeConditionOperator = New SqlToken
    getLeConditionOperator.Init "<=", SqlTokenType.OPERA_LE
End Function

' 获取表名 token
Private Function getTableNameToken() As SqlToken
    Set getTableNameToken = New SqlToken
    getTableNameToken.Init TEST_TABLE_NAME, SqlTokenType.STR_NAME
End Function

' 获取一个任意名称的 STR_NAME token
Private Function getStrNameToken(ByRef s As String) As SqlToken
    Set getStrNameToken = New SqlToken
    getStrNameToken.Init s, SqlTokenType.STR_NAME
End Function

' 获取一个逗号的元素
Private Function getCommaToken() As SqlToken
    Set getCommaToken = New SqlToken
    getCommaToken.Init ",", SqlTokenType.COMMA
End Function

' 获取一个单行注释元素
Private Function getSingleLineCommentToken(ByRef s As String) As SqlToken
    Set getSingleLineCommentToken = New SqlToken
    getSingleLineCommentToken.Init s, SqlTokenType.SINGLE_LINE_COMMENT
End Function

' 获取一个和前一个元素在同一行的注释元素
Private Function getShareLineCommentToken(ByRef s As String) As SqlToken
    Set getShareLineCommentToken = New SqlToken
    getShareLineCommentToken.Init s, SqlTokenType.SHARE_LINE_COMMENT
End Function

' 获取一个: [单行元素，和前一个元素在同一行的注释] 的组合元素
Private Function getOneTokenEndWithShareComment(ByRef s As String, ByRef comment As String) As ISqlFormatterElem
    Dim g As SqlFormatterCommaDeliMultiElem
    Set g = New SqlFormatterCommaDeliMultiElem

    Dim elem As ISqlFormatterElem
    Set elem = g

    ' 1. 增加一个单行元素
    elem.addComponent getStrNameToken(s)

    ' 2. 增加一个注释
    elem.addComponent getShareLineCommentToken(comment)

    Set getOneTokenEndWithShareComment = elem
End Function

' 获取一个: [多行元素，和前一个元素在同一行的注释] 的组合元素
' 多行连接的结果:
' col1 & ","
' col2 --commentX
Private Function getMultiLineEndWithShareComment() As ISqlFormatterElem
    Dim g As SqlFormatterCommaDeliMultiElem
    Set g = New SqlFormatterCommaDeliMultiElem

    Dim elem As ISqlFormatterElem
    Set elem = g

    ' 1. 增加一个单行元素
    elem.addComponent getStrNameToken("col1")

    ' 2. 手动设置为多行元素，仍然是单行
    g.setNeedMultiLineWhenHasComma True

    ' 3. 在末尾添加一个逗号元素，仍然是单行的
    elem.addComponent getCommaToken

    ' 4. 再增加一个单行元素，变成多行的
    elem.addComponent getStrNameToken("col2")

    elem.addComponent getShareLineCommentToken("--commentX")

    Set getMultiLineEndWithShareComment = elem
End Function

' 获取一个没有边界括号的多行元素
' 多行连接的结果:
' col1 & ","
' col2
Private Function getMultiLineElemNoParenthesis() As ISqlFormatterElem
    Dim g As SqlFormatterCommaDeliMultiElem
    Set g = New SqlFormatterCommaDeliMultiElem

    Dim elem As ISqlFormatterElem
    Set elem = g

    ' 1. 增加一个单行元素
    elem.addComponent getStrNameToken("col1")

    ' 2. 手动设置为多行元素，仍然是单行
    g.setNeedMultiLineWhenHasComma True

    ' 3. 在末尾添加一个逗号元素，仍然是单行的
    elem.addComponent getCommaToken

    ' 4. 再增加一个单行元素，变成多行的
    elem.addComponent getStrNameToken("col2")

    Set getMultiLineElemNoParenthesis = elem
End Function

' 获取一个多行的元素--包含边界括号
' 多行连接的结果:
' "("
' "    " & TEST_TABLE_NAME & ","
' "    " & TEST_TABLE_NAME
' ")"
Private Function getMultiLineElemWithBoundaryParenthesis() As ISqlFormatterElem
    Dim g As SqlFormatterCommaDeliMultiElem
    Set g = New SqlFormatterCommaDeliMultiElem

    Dim elem As ISqlFormatterElem
    Set elem = g

    ' ==============================
    ' 2. 单行变多行的测试
    ' ==============================
    ' 1. 增加一个单行元素
    elem.addComponent getTableNameToken

    ' 2. 手动设置为多行元素，仍然是单行
    g.setNeedMultiLineWhenHasComma True

    ' 3. 在末尾添加一个逗号元素，仍然是单行的
    elem.addComponent getCommaToken

    ' 4. 设置边界括号后，仍然是单行的
    elem.addBoundaryLeftParenthesis
    elem.addBoundaryRightParenthesis

    ' 5. 再增加一个单行元素，变成多行的
    elem.addComponent getTableNameToken

    Set getMultiLineElemWithBoundaryParenthesis = elem
End Function

' 获取一个只包含一个 token 组合
' 组合的拼接结果: xyz
Private Function getOneTokenArr() As IObjArrayRef
    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    ' xyz
    Dim token As SqlToken
    Set token = New SqlToken
    token.Init GET_ONE_TOKEN_ARRY_STR, SqlTokenType.STR_NAME
    result.Add token

    Set getOneTokenArr = result
End Function

' 获取一个 token 组合
' 组合的拼接结果: xyz, abc(c1, c2)
Private Function getTokenArr() As IObjArrayRef
    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    ' xyz
    Dim token As SqlToken
    Set token = New SqlToken
    token.Init GET_ONE_TOKEN_ARRY_STR, SqlTokenType.STR_NAME
    result.Add token

    ' ,
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' abc
    Set token = New SqlToken
    token.Init "abc", SqlTokenType.STR_NAME
    result.Add token

    '(
    Set token = New SqlToken
    token.Init "(", SqlTokenType.LEFT_PARENTHESIS
    result.Add token

    ' c1
    Set token = New SqlToken
    token.Init "c1", SqlTokenType.STR_NAME
    result.Add token

    ' ,
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' c2
    Set token = New SqlToken
    token.Init "c2", SqlTokenType.STR_NAME
    result.Add token

    ' )
    Set token = New SqlToken
    token.Init ")", SqlTokenType.RIGHT_PARENTHESIS
    result.Add token

    Set getTokenArr = result
End Function

' 获取一个 token 组合，并且这个组合的结果是多行的，并使用逗号分隔的
' 组合的拼接结果:
' xyz --comment1
' ,
' abc(c1, c2), --comment2 <<< 这里的 abc(c1, c2) 是一体的
' --comment3
Private Function getMultiLineCommaTokenArr() As IObjArrayRef
    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    ' xyz
    Dim token As SqlToken
    Set token = New SqlToken
    token.Init GET_ONE_TOKEN_ARRY_STR, SqlTokenType.STR_NAME
    result.Add token

    ' --comment1
    Set token = New SqlToken
    token.Init TEST_COMMENT_1, SqlTokenType.SHARE_LINE_COMMENT
    result.Add token

    ' ,
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' abc(c1, c2)
    Set token = New SqlToken
    token.Init "abc(c1, c2)", SqlTokenType.STR_NAME
    result.Add token

    ' ,
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' --comment2
    Set token = New SqlToken
    token.Init TEST_COMMENT_2, SqlTokenType.SHARE_LINE_COMMENT
    result.Add token

    ' --comment3
    Set token = New SqlToken
    token.Init TEST_COMMENT_3, SqlTokenType.SINGLE_LINE_COMMENT
    result.Add token

    Set getMultiLineCommaTokenArr = result
End Function

' 获取一个 token 组合: 一个同行注释 + 一个字符token
' 组合的拼接结果:
' --comment1 c1
Private Function getShareLineCommentAndStrTokenArr() As IObjArrayRef
    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    Dim token As SqlToken

    ' --comment1
    Set token = New SqlToken
    token.Init TEST_COMMENT_1, SqlTokenType.SHARE_LINE_COMMENT
    result.Add token

    ' c1
    Set token = New SqlToken
    token.Init "c1", SqlTokenType.STR_NAME
    result.Add token

    Set getShareLineCommentAndStrTokenArr = result
End Function

' 创建一个只有一个多行元素的数组
Private Function getOnlyMultiLineElemArr() As IObjArrayRef
    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    result.Add getMultiLineElemWithBoundaryParenthesis

    Set getOnlyMultiLineElemArr = result
End Function

' 创建一个包含多行元素的数组
' 数组的模式: 单行 --> [,] --> 多行
Private Function getHasMultiLineElemArr_Mode_A() As IObjArrayRef
    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    ' xyz
    Dim token As SqlToken
    Set token = New SqlToken
    token.Init GET_ONE_TOKEN_ARRY_STR, SqlTokenType.STR_NAME
    result.Add token

    ' 逗号
    ' ,
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' 多行元素
    result.Add getMultiLineElemWithBoundaryParenthesis

    Set getHasMultiLineElemArr_Mode_A = result
End Function

' 创建一个包含多行元素的数组
' 数组的模式: 多行 --> [,] --> 单行
Private Function getHasMultiLineElemArr_Mode_B() As IObjArrayRef
    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    ' 多行元素
    result.Add getMultiLineElemWithBoundaryParenthesis

    ' 逗号
    Dim token As SqlToken
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' xyz
    Set token = New SqlToken
    token.Init GET_ONE_TOKEN_ARRY_STR, SqlTokenType.STR_NAME
    result.Add token

    Set getHasMultiLineElemArr_Mode_B = result
End Function

' 创建一个包含多行元素的数组
' 数组的模式: 多行 --> 同一行的注释 --> [,] --> 多行 --> [,] --> 同一行的注释注释 --> 单行
Private Function getHasMultiLineElemArr_Mode_C() As IObjArrayRef
    Dim token As SqlToken

    Dim result As IObjArrayRef
    Set result = UtilsArrayRef.createRealObjArrayRef

    ' 多行
    result.Add getMultiLineElemWithBoundaryParenthesis

    ' 同一行的注释
    Set token = New SqlToken
    token.Init TEST_COMMENT_2, SqlTokenType.SHARE_LINE_COMMENT
    result.Add token

    ' [,]
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' 多行
    result.Add getMultiLineElemWithBoundaryParenthesis

    ' [,]
    Set token = New SqlToken
    token.Init ",", SqlTokenType.COMMA
    result.Add token

    ' 同一行的注释
    Set token = New SqlToken
    token.Init TEST_COMMENT_3, SqlTokenType.SHARE_LINE_COMMENT
    result.Add token

    ' 单行
    Set token = New SqlToken
    token.Init GET_ONE_TOKEN_ARRY_STR, SqlTokenType.STR_NAME
    result.Add token

    Set getHasMultiLineElemArr_Mode_C = result
End Function

' ======================================================================
' 测试用例
' ======================================================================
' 测试: 生成两个元素组成的 token组合
Private Sub test_createTwoElemTokenGroup()
    ' 1. 初始化
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim token01 As SqlToken
    Dim token02 As SqlToken

    Set token01 = New SqlToken
    token01.Init "with", SqlTokenType.KEY_WITH
    Set token02 = New SqlToken
    token02.Init "rollup", SqlTokenType.KEY_ROLLUP

    ' 2. 执行测试方法
    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.createTwoElemTokenGroup(token01, token02)

    ' 3. 检查结果
    Debug.Assert TypeOf elem Is SqlFormatterTokenGroup
    Debug.Assert elem.toString(config) = "with rollup"
End Sub

' 测试: 生成连续连接的字符串元素
Private Sub test_createContinuousStrElem()
    Dim elem As ISqlFormatterElem

    Set elem = SqlFormatterHelper.createContinuousStrElem

    Debug.Assert TypeOf elem Is SqlFormatterContinuousStrElem
End Sub

' 测试: 将一个对象包装为连续连接的字符串元素
Private Sub test_wrapperElemToContinuousStrElem()
    ' ==============================
    ' 1. 初始化
    ' ==============================
    Dim elem As ISqlFormatterElem

    Dim token01 As SqlToken
    Set token01 = New SqlToken
    token01.Init "c1", SqlTokenType.STR_NAME

    Dim token02 As SqlToken
    Set token02 = New SqlToken
    token02.Init ".", SqlTokenType.POINT

    Dim token03 As SqlToken
    Set token03 = New SqlToken
    token03.Init "c2", SqlTokenType.STR_NAME

    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    ' ==============================
    ' 2. 测试
    ' ==============================
    ' 1. 保证一个 token
    Set elem = SqlFormatterHelper.wrapperElemToContinuousStrElem(token01)

    Debug.Assert TypeOf elem Is SqlFormatterContinuousStrElem
    Debug.Assert elem.toString(config) = "c1"

    ' 2. 再添加一个 token
    elem.addComponent token02
    elem.addComponent token03
    Debug.Assert elem.toString(config) = "c1.c2"
End Sub

' 测试: 生成一个逗号分隔的多个元素
Private Sub test_createCommaDelimitMultiElem()
    Dim elem As ISqlFormatterElem
    ' ==============================
    ' 1. 测试: 单行时，遇到逗号不换行
    ' ==============================
    Set elem = SqlFormatterHelper.createCommaDelimitMultiElem

    ' 添加一个单行元素
    elem.addComponent getTableNameToken
    ' 添加一个逗号元素
    elem.addComponent getCommaToken
    ' 添加一个单行元素
    elem.addComponent getTableNameToken

    ' 仍然是单行的
    Debug.Assert elem.isMultiLine = False

    ' ==============================
    ' 2. 测试: 单行时，遇到逗号换行
    ' ==============================
    Set elem = SqlFormatterHelper.createCommaDelimitMultiElem(True)

    ' 添加一个单行元素
    elem.addComponent getTableNameToken
    ' 添加一个逗号元素
    elem.addComponent getCommaToken
    ' 添加一个单行元素
    elem.addComponent getTableNameToken

    ' 仍然是单行的
    Debug.Assert elem.isMultiLine = True
End Sub

' 测试: 生成一个容器作用域
Private Sub test_createContainerEnv()
    Dim elem As ISqlFormatterElem

    Set elem = SqlFormatterHelper.createContainerEnv
    Debug.Assert TypeOf elem Is SqlFormatterContainerEnv
End Sub

' 测试: 将一个作用域包装为容器作用域
Private Sub test_wrapperEnvToContainerEnv()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim token As SqlToken
    Set token = New SqlToken
    token.Init "select", SqlTokenType.KEY_SELECT

    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.wrapperEnvToContainerEnv(token)
    Debug.Assert TypeOf elem Is SqlFormatterContainerEnv
    Debug.Assert elem.getType = SqlTokenType.KEY_SELECT
    Debug.Assert elem.toString(config) = "select"
End Sub

' 测试: 生成一个key开始的作用域
Public Sub test_createKeyStartEnv()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim selectToken As SqlToken
    Set selectToken = New SqlToken
    selectToken.Init "select", SqlTokenType.KEY_SELECT

    Dim elem As SqlFormatterKeySectionEnv
    Set elem = SqlFormatterHelper.createKeyStartEnv(selectToken, SqlTokenType.KEY_SELECT)
    elem.ISqlFormatterElem_addComponent getStrNameToken("x1")
    Debug.Assert elem.ISqlFormatterElem_getType = SqlTokenType.KEY_SELECT


    Dim strArr As IPrimitiveArrayRef
    Set strArr = elem.ISqlFormatterElem_toStringArray(config)
    Debug.Assert strArr.Count = 2
    Debug.Assert strArr.Item(0) = "select"
    Debug.Assert strArr.Item(1) = "    x1"
End Sub

' 测试: 生成一个KeySectionEnv
Private Sub test_createKeySectionEnv()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim selectToken As SqlToken
    Set selectToken = New SqlToken
    selectToken.Init "select", SqlTokenType.KEY_SELECT

    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.createKeySectionEnv(selectToken, getStrNameToken("x1"))

    Debug.Assert TypeOf elem Is SqlFormatterKeySectionEnv

    Dim strArr As IPrimitiveArrayRef
    Set strArr = elem.toStringArray(config)
    Debug.Assert strArr.Count = 2
    Debug.Assert strArr.Item(0) = "select"
    Debug.Assert strArr.Item(1) = "    x1"
End Sub

' 测试: 将一个条件包装为多条件组合
Private Sub test_wrapToMultiConditions()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim c As SqlFormatterTwoElemCondition
    Set c = New SqlFormatterTwoElemCondition
    c.ISqlFormatterElem_addComponent getStrNameToken("x1")
    c.ISqlFormatterCondition_setConditionOperator getLeConditionOperator
    c.ISqlFormatterElem_addComponent getStrNameToken("x2")

    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.wrapToMultiConditions(c)

    Debug.Assert TypeOf elem Is SqlFormatterMultiConditions
    Debug.Assert elem.toString(config) = "x1 <= x2"
End Sub

' 测试: 创建一个多条件组合
Private Sub test_createMultiConditions()
    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.createMultiConditions

    Debug.Assert TypeOf elem Is SqlFormatterMultiConditions
End Sub

' 测试: 生成条件对象
Private Sub test_createCondition()
    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.createCondition

    Debug.Assert TypeOf elem Is SqlFormatterTwoElemCondition
End Sub

' 测试: 生成条件对象的条件运算符左侧的内容
Private Sub test_createConditionOnlyOpLeft()
    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.createConditionOnlyOpLeft(getStrNameToken("x1"), getLeConditionOperator)

    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Debug.Assert TypeOf elem Is SqlFormatterTwoElemCondition
    Debug.Assert elem.toString(config) = "x1 <="
End Sub

' 测试: 生成一个容器列
Private Sub test_createContainerCol()
    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.createContainerCol

    Debug.Assert TypeOf elem Is SqlFormatterContainerCol
    Debug.Assert elem.getType = SqlTokenType.NO_MEAN
End Sub

' 测试: 将一个列包装为容器列
Private Sub test_wrapperColToContainerCol()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim token As SqlToken
    Set token = New SqlToken
    token.Init "xxx", SqlTokenType.KEY_SELECT

    Dim elem As ISqlFormatterElem
    Set elem = SqlFormatterHelper.wrapperColToContainerCol(token)

    Debug.Assert TypeOf elem Is SqlFormatterContainerCol
    Debug.Assert elem.getType = SqlTokenType.KEY_SELECT
    Debug.Assert elem.toString(config) = "xxx"
End Sub

' 测试: 将一个列转换为表达式列
Private Sub test_transColToExprCol()
    Dim e As ISqlFormatterElem
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration
    ' ==============================
    ' 1. 测试列对象包装
    ' ==============================
    Dim token As SqlToken
    Set token = New SqlToken
    token.Init "abc", SqlTokenType.STR_NAME
    Set e = SqlFormatterHelper.transColToExprCol(token)

    Debug.Assert TypeOf e Is SqlFormatterExprCol

    ' ==============================
    ' 2. 测试直接返回
    ' ==============================
    Dim expr As SqlFormatterExprCol
    Set expr = New SqlFormatterExprCol

    Set e = SqlFormatterHelper.transColToExprCol(expr)
    Debug.Assert e Is expr

    ' ==============================
    ' 3. 测试参数是 null
    ' ==============================
    Set e = SqlFormatterHelper.transColToExprCol(Nothing)
    Debug.Assert e.toString(config) = ""
End Sub

' 测试: 生成一个函数列对象
Private Sub test_createFuncCol()
    ' ==============================
    ' 1. 初始化
    ' ==============================
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim token As SqlToken
    Set token = New SqlToken
    token.Init "max", SqlTokenType.STR_FUNC

    Dim func As SqlFormatterFuncCol
    Set func = SqlFormatterHelper.createFuncCol(token)

    ' ==============================
    ' 2. 检查初始化结果
    ' ==============================
    Debug.Assert func.ISqlFormatterElem_toString(config) = "max"
End Sub

' 测试: 生成一个case列对象
Private Sub test_createCaseCol()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim elem As SqlFormatterCaseCol

    Dim token As SqlToken
    Set token = New SqlToken
    token.Init "case", SqlTokenType.KEY_CASE

    Set elem = SqlFormatterHelper.createCaseCol(token)
    Debug.Assert elem.ISqlFormatterElem_toString(config) = "case"
End Sub

' 测试: 生成一个case的组成元素
Private Sub test_createCaseCompositionElem()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim elem As SqlFormatterCaseCompositionElem

    Dim token As SqlToken

    ' ==============================
    ' 1. when 初始化
    ' ==============================
    Set token = New SqlToken
    token.Init "when", SqlTokenType.KEY_WHEN

    Set elem = SqlFormatterHelper.createCaseCompositionElem(token)
    Debug.Assert elem.ISqlFormatterElem_toString(config) = "when"

    ' ==============================
    ' 2. else 初始化
    ' ==============================
    Set token = New SqlToken
    token.Init "else", SqlTokenType.KEY_ELSE

    Set elem = SqlFormatterHelper.createCaseCompositionElem(token)
    Debug.Assert elem.ISqlFormatterElem_toString(config) = "else"
End Sub

' 测试: 检查ON起始的作用域是不是ON_DUPLICATE作用域
Private Sub test_isOnDuplicateEnv()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: ON
    '    测试: 只有一个 ON，将会返回 false
    ' ==============================
    Set scanner = getObjArrayRefScanner(getOnToken)

    ' 1. 执行测试方法
    Debug.Assert SqlFormatterHelper.isOnDuplicateEnv(scanner) = False

    ' ==============================
    ' 2. 扫描器内是: on + STR_NAME
    '    测试: on 后面不是 duplicate，将会返回 false
    ' ==============================
    Set scanner = getObjArrayRefScanner(getOnToken, getStrNameToken("x1"))

    ' 1. 执行测试方法
    Debug.Assert SqlFormatterHelper.isOnDuplicateEnv(scanner) = False

    ' ==============================
    ' 3. 扫描器内是: on + duplicate
    '    测试: on 后面是 duplicate，将会返回 true
    ' ==============================
    Set scanner = getObjArrayRefScanner(getOnToken, getDuplicateToken)

    ' 1. 执行测试方法
    Debug.Assert SqlFormatterHelper.isOnDuplicateEnv(scanner) = True

End Sub

' 测试: 连接组成元素数组为一行字符串
Private Sub test_createFormatSingleStr()
    ' ==============================
    ' 1. 初始化
    ' ==============================
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim tokenArr As IObjArrayRef
    Set tokenArr = getTokenArr

    ' ==============================
    ' 2. 测试
    ' ==============================
    ' 无边界括号
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 0, 0) = GET_TOKEN_ARRY_STR
    ' 只存在左边界括号
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 1, 0) = "(" & GET_TOKEN_ARRY_STR
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 2, 0) = "((" & GET_TOKEN_ARRY_STR
    ' 只存在右边界括号
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 0, 1) = GET_TOKEN_ARRY_STR & ")"
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 0, 2) = GET_TOKEN_ARRY_STR & "))"
    ' 同时存在左右边界括号
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 1, 1) = "(" & GET_TOKEN_ARRY_STR & ")"
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 2, 2) = "((" & GET_TOKEN_ARRY_STR & "))"


    ' ==============================
    ' 2. 特殊 case: 一个左括号 + 一个同行注释
    ' ==============================
    Set tokenArr = UtilsArrayRef.createRealObjArrayRef
    tokenArr.Add createShareLineCommentToken("--c1")
    Debug.Assert SqlFormatterHelper.createFormatSingleStr(tokenArr, config, 1, 0) = "( --c1"

End Sub

' 测试: 以每个元素独占一行的形式生成字符串集合
Private Sub test_createElemExclusiveRowStrArr()
    ' ==============================
    ' 1. 初始化
    ' ==============================
    Dim prefixSpace As String
    prefixSpace = "    "
    Dim strArrRef As IPrimitiveArrayRef

    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim tokenArr As IObjArrayRef
    Set tokenArr = UtilsArrayRef.createRealObjArrayRef

    ' 创建元素数组
    ' 注释--和前一个元素在同一行 (测试 result.Count = 0)
    tokenArr.Add getShareLineCommentToken("--c1")
    ' 注释--单行注释
    tokenArr.Add getSingleLineCommentToken("--c2")
    ' 注释--和前一个元素在同一行 (前一行以注释结尾)
    tokenArr.Add getShareLineCommentToken("--c3")
    ' 单行元素 (测试单行元素)
    tokenArr.Add getStrNameToken("x1")
    ' 注释--和前一个元素在同一行 (测试 result.Count > 0)
    tokenArr.Add getShareLineCommentToken("--c4")
    ' 多行元素
    tokenArr.Add getMultiLineElemWithBoundaryParenthesis
    ' 单行元素
    tokenArr.Add getStrNameToken("x2")

    ' ==============================
    ' 2. 基础逻辑测试
    ' ==============================
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 0, 0)
    Debug.Assert strArrRef.Count = 9
    Debug.Assert strArrRef.Item(0) = "--c1"
    Debug.Assert strArrRef.Item(1) = "--c2"
    Debug.Assert strArrRef.Item(2) = "--c3"
    Debug.Assert strArrRef.Item(3) = "x1 --c4"
    Debug.Assert strArrRef.Item(4) = "("
    Debug.Assert strArrRef.Item(5) = "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(6) = "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(7) = ")"
    Debug.Assert strArrRef.Item(8) = "x2"

    ' ==============================
    ' 3. 附加括号测试
    ' ==============================
    Set tokenArr = UtilsArrayRef.createRealObjArrayRef

    ' 创建元素数组
    ' 注释--和前一个元素在同一行 (测试 result.Count = 0)
    tokenArr.Add getSingleLineCommentToken("--c1")
    ' 注释--单行注释
    tokenArr.Add getSingleLineCommentToken("--c2")
    ' 注释--和前一个元素在同一行 (前一行以注释结尾)
    tokenArr.Add getShareLineCommentToken("--c3")
    ' 单行元素 (测试单行元素)
    tokenArr.Add getStrNameToken("x1")
    ' 注释--和前一个元素在同一行 (测试 result.Count > 0)
    tokenArr.Add getShareLineCommentToken("--c4")
    ' 多行元素
    tokenArr.Add getMultiLineElemWithBoundaryParenthesis
    ' 单行元素
    tokenArr.Add getStrNameToken("x2")

    ' 1. 附加左括号
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 1, 0)
    Debug.Assert strArrRef.Count = 10
    Debug.Assert strArrRef.Item(0) = "("
    Debug.Assert strArrRef.Item(1) = prefixSpace & "--c1"
    Debug.Assert strArrRef.Item(2) = prefixSpace & "--c2"
    Debug.Assert strArrRef.Item(3) = prefixSpace & "--c3"
    Debug.Assert strArrRef.Item(4) = prefixSpace & "x1 --c4"
    Debug.Assert strArrRef.Item(5) = prefixSpace & "("
    Debug.Assert strArrRef.Item(6) = prefixSpace & "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(7) = prefixSpace & "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(8) = prefixSpace & ")"
    Debug.Assert strArrRef.Item(9) = prefixSpace & "x2"

    ' 2. 附加多个左括号
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 2, 0)
    Debug.Assert strArrRef.Count = 10
    Debug.Assert strArrRef.Item(0) = "(("
    Debug.Assert strArrRef.Item(1) = prefixSpace & "--c1"
    Debug.Assert strArrRef.Item(2) = prefixSpace & "--c2"
    Debug.Assert strArrRef.Item(3) = prefixSpace & "--c3"
    Debug.Assert strArrRef.Item(4) = prefixSpace & "x1 --c4"
    Debug.Assert strArrRef.Item(5) = prefixSpace & "("
    Debug.Assert strArrRef.Item(6) = prefixSpace & "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(7) = prefixSpace & "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(8) = prefixSpace & ")"
    Debug.Assert strArrRef.Item(9) = prefixSpace & "x2"

    ' 3. 附加一个右括号
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 0, 1)
    Debug.Assert strArrRef.Count = 10
    Debug.Assert strArrRef.Item(0) = prefixSpace & "--c1"
    Debug.Assert strArrRef.Item(1) = prefixSpace & "--c2"
    Debug.Assert strArrRef.Item(2) = prefixSpace & "--c3"
    Debug.Assert strArrRef.Item(3) = prefixSpace & "x1 --c4"
    Debug.Assert strArrRef.Item(4) = prefixSpace & "("
    Debug.Assert strArrRef.Item(5) = prefixSpace & "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(6) = prefixSpace & "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(7) = prefixSpace & ")"
    Debug.Assert strArrRef.Item(8) = prefixSpace & "x2"
    Debug.Assert strArrRef.Item(9) = ")"

    ' 4. 附加多个右括号
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 0, 2)
    Debug.Assert strArrRef.Count = 10
    Debug.Assert strArrRef.Item(0) = prefixSpace & "--c1"
    Debug.Assert strArrRef.Item(1) = prefixSpace & "--c2"
    Debug.Assert strArrRef.Item(2) = prefixSpace & "--c3"
    Debug.Assert strArrRef.Item(3) = prefixSpace & "x1 --c4"
    Debug.Assert strArrRef.Item(4) = prefixSpace & "("
    Debug.Assert strArrRef.Item(5) = prefixSpace & "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(6) = prefixSpace & "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(7) = prefixSpace & ")"
    Debug.Assert strArrRef.Item(8) = prefixSpace & "x2"
    Debug.Assert strArrRef.Item(9) = "))"

    ' 5. 附加左右边界括号--附加 1 个
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 1, 1)
    Debug.Assert strArrRef.Count = 11
    Debug.Assert strArrRef.Item(0) = "("
    Debug.Assert strArrRef.Item(1) = prefixSpace & "--c1"
    Debug.Assert strArrRef.Item(2) = prefixSpace & "--c2"
    Debug.Assert strArrRef.Item(3) = prefixSpace & "--c3"
    Debug.Assert strArrRef.Item(4) = prefixSpace & "x1 --c4"
    Debug.Assert strArrRef.Item(5) = prefixSpace & "("
    Debug.Assert strArrRef.Item(6) = prefixSpace & "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(7) = prefixSpace & "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(8) = prefixSpace & ")"
    Debug.Assert strArrRef.Item(9) = prefixSpace & "x2"
    Debug.Assert strArrRef.Item(10) = ")"

    ' 6. 附加左右边界括号--附加多个
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 2, 2)
    Debug.Assert strArrRef.Count = 11
    Debug.Assert strArrRef.Item(0) = "(("
    Debug.Assert strArrRef.Item(1) = prefixSpace & "--c1"
    Debug.Assert strArrRef.Item(2) = prefixSpace & "--c2"
    Debug.Assert strArrRef.Item(3) = prefixSpace & "--c3"
    Debug.Assert strArrRef.Item(4) = prefixSpace & "x1 --c4"
    Debug.Assert strArrRef.Item(5) = prefixSpace & "("
    Debug.Assert strArrRef.Item(6) = prefixSpace & "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(7) = prefixSpace & "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(8) = prefixSpace & ")"
    Debug.Assert strArrRef.Item(9) = prefixSpace & "x2"
    Debug.Assert strArrRef.Item(10) = "))"

    ' ==============================
    ' 4. 测试：特殊case: 左括号 + 同行注释 + 一个字符token
    ' ==============================
    Set tokenArr = getShareLineCommentAndStrTokenArr
    ' 只有左括号
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 1, 0)
    Debug.Assert strArrRef.Count = 2
    Debug.Assert strArrRef.Item(0) = "( --comment1"
    Debug.Assert strArrRef.Item(1) = "    c1"

    ' 只有右括号
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 0, 1)
    Debug.Assert strArrRef.Count = 3
    Debug.Assert strArrRef.Item(0) = "    --comment1"
    Debug.Assert strArrRef.Item(1) = "    c1"
    Debug.Assert strArrRef.Item(2) = ")"

    ' 同时有左右括号
    Set strArrRef = SqlFormatterHelper.createElemExclusiveRowStrArr(tokenArr, config, 1, 1)
    Debug.Assert strArrRef.Count = 3
    Debug.Assert strArrRef.Item(0) = "( --comment1"
    Debug.Assert strArrRef.Item(1) = "    c1"
    Debug.Assert strArrRef.Item(2) = ")"
End Sub

' 测试: 以每个元素独占一行的形式填充字符串集合
Private Sub test_fullElemExclusiveRowStrArr()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim strArrRef As IPrimitiveArrayRef
    Set strArrRef = UtilsArrayRef.createRealPrimitiveArrayRef

    Dim tokenArr As IObjArrayRef
    Set tokenArr = UtilsArrayRef.createRealObjArrayRef

    ' ==============================
    ' 1. 基础逻辑测试
    ' ==============================
    ' 创建元素数组
    ' 注释--和前一个元素在同一行 (测试 result.Count = 0)
    tokenArr.Add getShareLineCommentToken("--c1")
    ' 注释--单行注释
    tokenArr.Add getSingleLineCommentToken("--c2")
    ' 注释--和前一个元素在同一行 (前一行以注释结尾)
    tokenArr.Add getShareLineCommentToken("--c3")
    ' 单行元素 (测试单行元素)
    tokenArr.Add getStrNameToken("x1")
    ' 注释--和前一个元素在同一行 (测试 result.Count > 0)
    tokenArr.Add getShareLineCommentToken("--c4")
    ' 多行元素
    tokenArr.Add getMultiLineElemWithBoundaryParenthesis
    ' 单行元素
    tokenArr.Add getStrNameToken("x2")

    Debug.Assert strArrRef.Count = 0
    SqlFormatterHelper.fullElemExclusiveRowStrArr strArrRef, tokenArr, config, ""
    Debug.Assert strArrRef.Count = 9
    Debug.Assert strArrRef.Item(0) = "--c1"
    Debug.Assert strArrRef.Item(1) = "--c2"
    Debug.Assert strArrRef.Item(2) = "--c3"
    Debug.Assert strArrRef.Item(3) = "x1 --c4"
    Debug.Assert strArrRef.Item(4) = "("
    Debug.Assert strArrRef.Item(5) = "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(6) = "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(7) = ")"
    Debug.Assert strArrRef.Item(8) = "x2"

    ' ==============================
    ' 2. 附加前缀空格
    ' ==============================
    Set strArrRef = UtilsArrayRef.createRealPrimitiveArrayRef
    Dim prefixSpace As String
    prefixSpace = "   "
    Debug.Assert strArrRef.Count = 0
    SqlFormatterHelper.fullElemExclusiveRowStrArr strArrRef, tokenArr, config, prefixSpace
    Debug.Assert strArrRef.Count = 9
    Debug.Assert strArrRef.Item(0) = prefixSpace & "--c1"
    Debug.Assert strArrRef.Item(1) = prefixSpace & "--c2"
    Debug.Assert strArrRef.Item(2) = prefixSpace & "--c3"
    Debug.Assert strArrRef.Item(3) = prefixSpace & "x1 --c4"
    Debug.Assert strArrRef.Item(4) = prefixSpace & "("
    Debug.Assert strArrRef.Item(5) = prefixSpace & "    " & TEST_TABLE_NAME & ","
    Debug.Assert strArrRef.Item(6) = prefixSpace & "    " & TEST_TABLE_NAME
    Debug.Assert strArrRef.Item(7) = prefixSpace & ")"
    Debug.Assert strArrRef.Item(8) = prefixSpace & "x2"

    ' ==============================
    ' 3. 测试：特殊case: 左括号 + 同行注释 + 一个字符token
    ' ==============================
    ' 预先向字符串集合中增加一个左括号
    Set strArrRef = UtilsArrayRef.createRealPrimitiveArrayRef
    strArrRef.Add "("
    Set tokenArr = getShareLineCommentAndStrTokenArr

    ' 这里为了模拟出现左括号的情况，所以手动设置前缀空格字符串为 4 个空格
    SqlFormatterHelper.fullElemExclusiveRowStrArr strArrRef, tokenArr, config, "    "
    Debug.Assert strArrRef.Count = 2
    Debug.Assert strArrRef.Item(0) = "( --comment1"
    Debug.Assert strArrRef.Item(1) = "    c1"
End Sub

' 测试: 以连续连接元素的方式生成字符串集合
Private Sub test_createElemContinuousStrArr()
    ' ==============================
    ' 1. 初始化
    ' ==============================
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim tokenArr As IObjArrayRef
    Dim result As IPrimitiveArrayRef

    ' ==============================
    ' 2. 测试： 基础功能测试
    ' ==============================
    Set tokenArr = UtilsArrayRef.createRealObjArrayRef

    ' 创建元素数组
    ' 注释 -- 和前一个元素在同一行的注释 -- 4.3-1.2 -- 第一个元素
    tokenArr.Add getShareLineCommentToken("--c1")
    ' 单行元素
    tokenArr.Add getStrNameToken("x1")
    ' 注释 -- 和前一个元素在同一行的注释 -- 4.3-1.1
    tokenArr.Add getShareLineCommentToken("--c2")
    ' 注释 -- 和前一个元素在同一行的注释 -- 4.3-1.2 -- 前面的内容已经保存到结果集合了
    tokenArr.Add getShareLineCommentToken("--c3")
    ' 单行元素
    tokenArr.Add getStrNameToken("x2")
    ' 多行元素 -- 单行和多行的第一行连接
    tokenArr.Add getMultiLineElemNoParenthesis
    ' 单行元素 -- 多行的最后一行和单行连接
    tokenArr.Add getStrNameToken("x3")
    ' 单行注释
    tokenArr.Add getSingleLineCommentToken("--c4")
    ' 以注释结尾的[单行元素]
    tokenArr.Add getOneTokenEndWithShareComment("x4", "--c5")
    ' 单行元素 -- 注释结尾后，单行元素应该在新的一行上
    tokenArr.Add getStrNameToken("x5")
    ' 以注释结尾的[多行元素]
    tokenArr.Add getMultiLineEndWithShareComment
    ' 单行元素 -- 注释结尾后，单行元素应该在新的一行上
    tokenArr.Add getStrNameToken("x6")

    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 0, 0)
    Debug.Assert result.Count = 10
    Debug.Assert result.Item(0) = "--c1"
    Debug.Assert result.Item(1) = "x1 --c2"
    Debug.Assert result.Item(2) = "--c3"
    Debug.Assert result.Item(3) = "x2 col1,"
    Debug.Assert result.Item(4) = "col2 x3"
    Debug.Assert result.Item(5) = "--c4"
    Debug.Assert result.Item(6) = "x4 --c5"
    Debug.Assert result.Item(7) = "x5 col1,"
    Debug.Assert result.Item(8) = "col2 --commentX"
    Debug.Assert result.Item(9) = "x6"

    ' ==============================
    ' 3. 测试： 边界括号测试
    ' ==============================
    Dim prefixSpace As String
    prefixSpace = "    "
    Set tokenArr = UtilsArrayRef.createRealObjArrayRef
    ' 单行元素
    tokenArr.Add getStrNameToken("x1")
    ' 多行元素 -- 单行和多行的第一行连接
    tokenArr.Add getMultiLineElemNoParenthesis
    ' 单行元素 -- 多行的最后一行和单行连接
    tokenArr.Add getStrNameToken("x2")

    ' 只存在左边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 1, 0)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = prefixSpace & "x1 col1,"
    Debug.Assert result.Item(2) = prefixSpace & "col2 x2"

    ' 只存在左边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 2, 0)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = prefixSpace & "x1 col1,"
    Debug.Assert result.Item(2) = prefixSpace & "col2 x2"

    ' 只存在右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 0, 1)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = prefixSpace & "x1 col1,"
    Debug.Assert result.Item(1) = prefixSpace & "col2 x2"
    Debug.Assert result.Item(2) = ")"

    ' 只存在右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 0, 2)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = prefixSpace & "x1 col1,"
    Debug.Assert result.Item(1) = prefixSpace & "col2 x2"
    Debug.Assert result.Item(2) = "))"

    ' 存在左右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 1, 1)
    Debug.Assert result.Count = 4
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = prefixSpace & "x1 col1,"
    Debug.Assert result.Item(2) = prefixSpace & "col2 x2"
    Debug.Assert result.Item(3) = ")"

    ' 只存在右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 2, 2)
    Debug.Assert result.Count = 4
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = prefixSpace & "x1 col1,"
    Debug.Assert result.Item(2) = prefixSpace & "col2 x2"
    Debug.Assert result.Item(3) = "))"

    ' ==============================
    ' 4. 测试：特殊case: 左括号 + 同行注释 + 一个字符token
    ' ==============================
    Set tokenArr = getShareLineCommentAndStrTokenArr
    ' 只有左括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 1, 0)
    Debug.Assert result.Count = 2
    Debug.Assert result.Item(0) = "( --comment1"
    Debug.Assert result.Item(1) = "    c1"

    ' 只有右括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 0, 1)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "    --comment1"
    Debug.Assert result.Item(1) = "    c1"
    Debug.Assert result.Item(2) = ")"

    ' 同时有左右括号
    Set result = SqlFormatterHelper.createElemContinuousStrArr(tokenArr, config, 1, 1)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "( --comment1"
    Debug.Assert result.Item(1) = "    c1"
    Debug.Assert result.Item(2) = ")"
End Sub

' 测试: 以连续连接和逗号换行的方式生成字符串集合
Private Sub test_createElemContinuousAndDelimitByCommaStrArr()
    ' ==============================
    ' 1. 初始化
    ' ==============================
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim tokenArr As IObjArrayRef
    Dim result As IPrimitiveArrayRef

    ' ==============================
    ' 2. 测试： 数组中有多个元素
    ' ==============================
    Set tokenArr = getMultiLineCommaTokenArr

    ' 无边界括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 0)
    Debug.Assert result.Count = 4
    Debug.Assert result.Item(0) = GET_ONE_TOKEN_ARRY_STR & " " & TEST_COMMENT_1
    Debug.Assert result.Item(1) = ","
    Debug.Assert result.Item(2) = "abc(c1, c2), " & TEST_COMMENT_2
    Debug.Assert result.Item(3) = TEST_COMMENT_3

    ' 只存在左边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 0)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR & " " & TEST_COMMENT_1
    Debug.Assert result.Item(2) = "    ,"
    Debug.Assert result.Item(3) = "    abc(c1, c2), " & TEST_COMMENT_2
    Debug.Assert result.Item(4) = "    " & TEST_COMMENT_3

    ' 只存在左边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 2, 0)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR & " " & TEST_COMMENT_1
    Debug.Assert result.Item(2) = "    ,"
    Debug.Assert result.Item(3) = "    abc(c1, c2), " & TEST_COMMENT_2
    Debug.Assert result.Item(4) = "    " & TEST_COMMENT_3

    ' 只存在右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 1)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "    " & GET_ONE_TOKEN_ARRY_STR & " " & TEST_COMMENT_1
    Debug.Assert result.Item(1) = "    ,"
    Debug.Assert result.Item(2) = "    abc(c1, c2), " & TEST_COMMENT_2
    Debug.Assert result.Item(3) = "    " & TEST_COMMENT_3
    Debug.Assert result.Item(4) = ")"

    ' 只存在右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 2)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "    " & GET_ONE_TOKEN_ARRY_STR & " " & TEST_COMMENT_1
    Debug.Assert result.Item(1) = "    ,"
    Debug.Assert result.Item(2) = "    abc(c1, c2), " & TEST_COMMENT_2
    Debug.Assert result.Item(3) = "    " & TEST_COMMENT_3
    Debug.Assert result.Item(4) = "))"

    ' 同时存在左右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 1)
    Debug.Assert result.Count = 6
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR & " " & TEST_COMMENT_1
    Debug.Assert result.Item(2) = "    ,"
    Debug.Assert result.Item(3) = "    abc(c1, c2), " & TEST_COMMENT_2
    Debug.Assert result.Item(4) = "    " & TEST_COMMENT_3
    Debug.Assert result.Item(5) = ")"

    ' 同时存在左右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 2, 2)
    Debug.Assert result.Count = 6
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR & " " & TEST_COMMENT_1
    Debug.Assert result.Item(2) = "    ,"
    Debug.Assert result.Item(3) = "    abc(c1, c2), " & TEST_COMMENT_2
    Debug.Assert result.Item(4) = "    " & TEST_COMMENT_3
    Debug.Assert result.Item(5) = "))"

    ' ==============================
    ' 3. 测试： 数组中只有一个单行元素
    ' ==============================
    Set tokenArr = getOneTokenArr
    ' 无边界括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 0)
    Debug.Assert result.Count = 1
    Debug.Assert result.Item(0) = GET_ONE_TOKEN_ARRY_STR

    ' 只存在左边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 0)
    Debug.Assert result.Count = 2
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR

    ' 只存在左边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 2, 0)
    Debug.Assert result.Count = 2
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR

    ' 只存在右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 1)
    Debug.Assert result.Count = 2
    Debug.Assert result.Item(0) = "    " & GET_ONE_TOKEN_ARRY_STR
    Debug.Assert result.Item(1) = ")"

    ' 只存在右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 2)
    Debug.Assert result.Count = 2
    Debug.Assert result.Item(0) = "    " & GET_ONE_TOKEN_ARRY_STR
    Debug.Assert result.Item(1) = "))"

    ' 同时存在左右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 1)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR
    Debug.Assert result.Item(2) = ")"

    ' 同时存在左右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 2, 2)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = "    " & GET_ONE_TOKEN_ARRY_STR
    Debug.Assert result.Item(2) = "))"

    ' ==============================
    ' 4. 测试： 数组中只有一个多行元素
    ' ==============================
    Set tokenArr = getOnlyMultiLineElemArr
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 0)

    Debug.Assert result.Count = 4
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(2) = "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(3) = ")"

    ' 只存在左边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 0)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & "("
    Debug.Assert result.Item(2) = "    " & "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(3) = "    " & "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(4) = "    " & ")"

    ' 只存在左边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 2, 0)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = "    " & "("
    Debug.Assert result.Item(2) = "    " & "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(3) = "    " & "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(4) = "    " & ")"

    ' 只存在右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 1)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "    " & "("
    Debug.Assert result.Item(1) = "    " & "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(2) = "    " & "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(3) = "    " & ")"
    Debug.Assert result.Item(4) = ")"

    ' 只存在右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 2)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "    " & "("
    Debug.Assert result.Item(1) = "    " & "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(2) = "    " & "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(3) = "    " & ")"
    Debug.Assert result.Item(4) = "))"

    ' 同时存在左右边界括号--1个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 1)
    Debug.Assert result.Count = 6
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & "("
    Debug.Assert result.Item(2) = "    " & "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(3) = "    " & "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(4) = "    " & ")"
    Debug.Assert result.Item(5) = ")"

    ' 同时存在左右边界括号--2个括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 2, 2)
    Debug.Assert result.Count = 6
    Debug.Assert result.Item(0) = "(("
    Debug.Assert result.Item(1) = "    " & "("
    Debug.Assert result.Item(2) = "    " & "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(3) = "    " & "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(4) = "    " & ")"
    Debug.Assert result.Item(5) = "))"

    ' ==============================
    ' 5. 测试： 数组的模式: 单行 --> [,] --> 多行
    ' ==============================
    Set tokenArr = getHasMultiLineElemArr_Mode_A
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 0)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = GET_ONE_TOKEN_ARRY_STR & ","
    Debug.Assert result.Item(1) = "("
    Debug.Assert result.Item(2) = "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(3) = "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(4) = ")"

    ' ==============================
    ' 6. 测试： 数组的模式: 多行 --> [,] --> 单行
    ' ==============================
    Set tokenArr = getHasMultiLineElemArr_Mode_B
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 0)
    Debug.Assert result.Count = 5
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(2) = "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(3) = "),"
    Debug.Assert result.Item(4) = GET_ONE_TOKEN_ARRY_STR

    ' ==============================
    ' 7. 测试： 数组的模式: 多行 --> 同一行的注释 --> [,] --> 多行 --> [,] --> 同一行的注释注释 --> 单行
    ' ==============================
    Set tokenArr = getHasMultiLineElemArr_Mode_C
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 0)
    Debug.Assert result.Count = 10
    Debug.Assert result.Item(0) = "("
    Debug.Assert result.Item(1) = "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(2) = "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(3) = ") " & TEST_COMMENT_2 ' 第一个多行结束 + 第一个同一行的注释
    Debug.Assert result.Item(4) = "," ' 第一个逗号
    Debug.Assert result.Item(5) = "("
    Debug.Assert result.Item(6) = "    " & TEST_TABLE_NAME & ","
    Debug.Assert result.Item(7) = "    " & TEST_TABLE_NAME
    Debug.Assert result.Item(8) = "), " & TEST_COMMENT_3  ' 第二个多行结束 + 第二个逗号 + 第二个注释
    Debug.Assert result.Item(9) = GET_ONE_TOKEN_ARRY_STR  ' 最后一个单行元素

    ' ==============================
    ' 8. 测试：特殊case: 左括号 + 同行注释 + 一个字符token
    ' ==============================
    Set tokenArr = getShareLineCommentAndStrTokenArr
    ' 只有左括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 0)
    Debug.Assert result.Count = 2
    Debug.Assert result.Item(0) = "( --comment1"
    Debug.Assert result.Item(1) = "    c1"

    ' 只有右括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 0, 1)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "    --comment1"
    Debug.Assert result.Item(1) = "    c1"
    Debug.Assert result.Item(2) = ")"

    ' 同时有左右括号
    Set result = SqlFormatterHelper.createElemContinuousAndDelimitByCommaStrArr(tokenArr, config, 1, 1)
    Debug.Assert result.Count = 3
    Debug.Assert result.Item(0) = "( --comment1"
    Debug.Assert result.Item(1) = "    c1"
    Debug.Assert result.Item(2) = ")"
End Sub

' 测试: 连接对齐元素中的组成元素并填充到结果集合
Private Sub test_fullAndJoinArrayElem()
    Dim config As SqlFormatterConfiguration
    Set config = New SqlFormatterConfiguration

    Dim componentArray As IObjArrayRef
    Dim resultArray As IPrimitiveArrayRef

    ' ==============================
    ' 1. 元素数组为空
    '    startStr = ""
    '    测试: 空元素集合可以正常结束
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "", ""

    Debug.Assert resultArray.Count = 0

    ' ==============================
    ' 2. 元素数组: 一个注释
    '    startStr = ""
    '    测试只有一个注释
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add createShareLineCommentToken("--c1")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "", ""

    Debug.Assert resultArray.Count = 1
    Debug.Assert resultArray.Item(0) = "--c1"

    ' ==============================
    ' 3. 元素数组: 一个同行注释
    '    startStr = "x1"
    '    测试: 同行注释可以连接到 startStr 后面
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add createShareLineCommentToken("--c1")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "x1", ""

    Debug.Assert resultArray.Count = 1
    Debug.Assert resultArray.Item(0) = "x1 --c1"

    ' ==============================
    ' 4. 元素数组: STR_NAME + 一个注释
    '    startStr = ""
    '    测试: STR_NAME 可以连接到 startStr 后面
    '    测试: 同行注释可以连接到 STR_NAME 后面
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add getStrNameToken("x1")
    componentArray.Add createShareLineCommentToken("--c1")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "", ""

    Debug.Assert resultArray.Count = 1
    Debug.Assert resultArray.Item(0) = "x1 --c1"

    ' ==============================
    ' 5. 元素数组: 一个同行注释 + STR_NAME
    '    startStr = "x1", extraSpaceAfterFirstSave="    "
    '    测试: 注释后的 STR_NAME 会换行 + 换行后，前面会增加 extraSpaceAfterFirstSave
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add createShareLineCommentToken("--c1")
    componentArray.Add getStrNameToken("y")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "x1", "    "

    Debug.Assert resultArray.Count = 2
    Debug.Assert resultArray.Item(0) = "x1 --c1"
    Debug.Assert resultArray.Item(1) = "    y"

    ' ==============================
    ' 6. 元素数组: 一个同行注释 + STR_NAME + 一个同行注释 + STR_NAME
    '    startStr = "x1", extraSpaceAfterFirstSave="    "
    '    测试注释导致的换行只会增加一次 extraSpaceAfterFirstSave
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add createShareLineCommentToken("--c1")
    componentArray.Add getStrNameToken("y")
    componentArray.Add createShareLineCommentToken("--c2")
    componentArray.Add getStrNameToken("z")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "x1", "    "

    Debug.Assert resultArray.Count = 3
    Debug.Assert resultArray.Item(0) = "x1 --c1"
    Debug.Assert resultArray.Item(1) = "    y --c2"
    Debug.Assert resultArray.Item(2) = "    z"

    ' ==============================
    ' 7. 元素数组: 一个单行注释 + STR_NAME
    '    startStr = "x1", extraSpaceAfterFirstSave="    "
    '    测试: 单行注释不会连接到前面的元素
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add createSingleLineCommentToken("--c1")
    componentArray.Add getStrNameToken("y")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "x1", "    "

    Debug.Assert resultArray.Count = 3
    Debug.Assert resultArray.Item(0) = "x1"
    Debug.Assert resultArray.Item(1) = "    --c1"
    Debug.Assert resultArray.Item(2) = "    y"

    ' ==============================
    ' 8. 元素数组: 一个单行注释 + STR_NAME
    '    startStr = "", extraSpaceAfterFirstSave="    "
    '    测试: 单行注释前面没有内容，并在第一行 + 产生换行，后面的元素前面会附加 + extraSpaceAfterFirstSave
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add createSingleLineCommentToken("--c1")
    componentArray.Add getStrNameToken("y")
    componentArray.Add createSingleLineCommentToken("--c2")
    componentArray.Add getStrNameToken("z")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "", "    "

    Debug.Assert resultArray.Count = 4
    Debug.Assert resultArray.Item(0) = "--c1"
    Debug.Assert resultArray.Item(1) = "    y"
    Debug.Assert resultArray.Item(2) = "    --c2"
    Debug.Assert resultArray.Item(3) = "    z"

    ' ==============================
    ' 9. 元素数组: STR_NAME + 一个单行注释
    '    startStr = "", extraSpaceAfterFirstSave="    "
    '    测试: 单行注释不会连接到前面的元素
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add getStrNameToken("x1")
    componentArray.Add createSingleLineCommentToken("--c1")
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "", "    "

    Debug.Assert resultArray.Count = 2
    Debug.Assert resultArray.Item(0) = "x1"
    Debug.Assert resultArray.Item(1) = "    --c1"

    ' ==============================
    ' 10. 元素数组: STR_NAME + 一个多行元素
    '    startStr = "", extraSpaceAfterFirstSave="    "
    '    测试: STR_NAME 会连接到多行元素的第一行前面
    ' ==============================
    Set componentArray = UtilsArrayRef.createRealObjArrayRef
    componentArray.Add getStrNameToken("x1")
    componentArray.Add getMultiLineElemNoParenthesis
    Set resultArray = UtilsArrayRef.createRealPrimitiveArrayRef

    SqlFormatterHelper.fullAndJoinArrayElem config, componentArray, _
        resultArray, "", "", "    "

    Debug.Assert resultArray.Count = 2
    Debug.Assert resultArray.Item(0) = "x1 col1,"
    Debug.Assert resultArray.Item(1) = "    col2"

End Sub

' 测试: 通用方法--连接两个元素的字符串
Private Sub test_joinTwoElemStr()
    ' 测试: 如果 `prev` 是空字符串 `prev == ""`，则返回 `cur`
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("", "abc") = "abc"

    ' 测试: 如果 `cur == ","`，则返回 `prev + cur`
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xyz", ",") = "xyz,"

    ' 测试: 如果 `cur == "("`，则返回 `prev + " " + cur`
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xyz", "(") = "xyz ("

    ' 测试: 如果 `cur == ")"`，则返回 `prev + cur`
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xyz", ")") = "xyz)"

    ' 测试: 如果 `prev 的最后一个字符 == " "`，则返回 `prev + cur`
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xyz ", "abc") = "xyz abc"

    ' 测试: 如果 `prev 的最后一个字符 == "("`，则返回 `prev + cur`
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xyz(", "abc") = "xyz(abc"

    ' 测试: 如果 `prev 的最后一个字符 != "(" || " "`，则返回 `prev + " " + cur`
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xyz", "abc") = "xyz abc"

    ' 测试: 运算符 + (
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("a +", "(") = "a + ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("a -", "(") = "a - ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("a *", "(") = "a * ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("a /", "(") = "a / ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("a |", "(") = "a | ("

    ' 测试: Not/And/Or/As + (
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("and not", "(") = "and not ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("and Not", "(") = "and Not ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("and", "(") = "and ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("And", "(") = "And ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xx or", "(") = "xx or ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xx Or", "(") = "xx Or ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xx as", "(") = "xx as ("
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("xx As", "(") = "xx As ("

    ' 测试 ( + 注释
    Debug.Assert SqlFormatterHelper.joinTwoElemStr("(", "--c1") = "( --c1"
End Sub

' ==================================================
' 计算元素的偏移量
' ==================================================
' 测试: 获取左括号栈中下一个左括号的偏移量
Private Sub test_getLeftParenthesisOffsetInStack()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    Dim stack As ObjStack

    ' ==============================
    ' 1. 左括号栈内是: 空
    ' ==============================
    ' 1. 创建左括号栈
    Set stack = New ObjStack
    ' 2. 执行测试方法
    offset = SqlFormatterHelper.getLeftParenthesisOffsetInStack(stack)
    ' 3. 检查结果
    Debug.Assert offset = 0
    Debug.Assert stack.Count = 0

    ' ==============================
    ' 2. 左括号栈内是: [栈顶]一个左括号[栈底]
    ' ==============================
    ' 1. 创建左括号栈
    Set stack = New ObjStack
    stack.push getLeftParenthesisToken
    ' 2. 执行测试方法
    offset = SqlFormatterHelper.getLeftParenthesisOffsetInStack(stack)
    ' 3. 检查结果
    Debug.Assert offset = 1
    Debug.Assert stack.Count = 1

    ' ==============================
    ' 3. 左括号栈内是: [栈顶]一个左括号 + 一个注释[栈底]
    ' ==============================
    ' 1. 创建左括号栈
    Set stack = New ObjStack
    stack.push createShareLineCommentToken("--c1")
    stack.push getLeftParenthesisToken
    ' 2. 执行测试方法
    offset = SqlFormatterHelper.getLeftParenthesisOffsetInStack(stack)
    ' 3. 检查结果
    Debug.Assert offset = 1
    Debug.Assert stack.Count = 2

    ' ==============================
    ' 4. 左括号栈内是: [栈顶]一个注释 + 一个左括号[栈底]
    '    测试左括号前面有一个注释
    ' ==============================
    ' 1. 创建左括号栈
    Set stack = New ObjStack
    stack.push getLeftParenthesisToken
    stack.push createShareLineCommentToken("--c1")
    ' 2. 执行测试方法
    offset = SqlFormatterHelper.getLeftParenthesisOffsetInStack(stack)
    ' 3. 检查结果
    Debug.Assert offset = 2
    Debug.Assert stack.Count = 2

    ' ==============================
    ' 5. 左括号栈内是: [栈顶]一个注释 + 一个左括号[栈底]
    '    测试左括号前面有多个注释
    ' ==============================
    ' 1. 创建左括号栈
    Set stack = New ObjStack
    stack.push getLeftParenthesisToken
    stack.push createShareLineCommentToken("--c1")
    stack.push createShareLineCommentToken("--c2")
    ' 2. 执行测试方法
    offset = SqlFormatterHelper.getLeftParenthesisOffsetInStack(stack)
    ' 3. 检查结果
    Debug.Assert offset = 3
    Debug.Assert stack.Count = 3

    ' ==============================
    ' 6. 左括号栈内是: [栈顶]一个注释 + 一个注释[栈底]
    '    测试没有左括号
    ' ==============================
    ' 1. 创建左括号栈
    Set stack = New ObjStack
    stack.push createShareLineCommentToken("--c1")
    stack.push createShareLineCommentToken("--c2")
    ' 2. 执行测试方法
    offset = SqlFormatterHelper.getLeftParenthesisOffsetInStack(stack)
    ' 3. 检查结果
    Debug.Assert offset = 0
    Debug.Assert stack.Count = 2

    ' ==============================
    ' 7. 左括号栈内是: [栈顶]一个注释 + 一个括号 + 一个括号[栈底]
    '    测试有多个左括号时，返回第一个左括号的偏移量
    ' ==============================
    ' 1. 创建左括号栈
    Set stack = New ObjStack
    stack.push createShareLineCommentToken("--c1")
    stack.push getLeftParenthesisToken
    stack.push getLeftParenthesisToken

    ' 2. 执行测试方法
    offset = SqlFormatterHelper.getLeftParenthesisOffsetInStack(stack)
    ' 3. 检查结果
    Debug.Assert offset = 1
    Debug.Assert stack.Count = 3
End Sub

' 测试: 获取扫描器到下一个最近的逗号的偏移量
Private Sub test_getNextCommaOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: 逗号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getCommaToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextCommaOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0


    ' ==============================
    ' 2. 扫描器内是: 注释 + 逗号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getCommaToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextCommaOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非逗号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextCommaOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextCommaOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非逗号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextLeftParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的左括号的偏移量
Private Sub test_getNextLeftParenthesisOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: 左括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getLeftParenthesisToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextLeftParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0


    ' ==============================
    ' 2. 扫描器内是: 注释 + 左括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getLeftParenthesisToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextLeftParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非左括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextLeftParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextLeftParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非左括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextLeftParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的右括号的偏移量
Private Sub test_getNextRightParenthesisOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: 右括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getRightParenthesisToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRightParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0


    ' ==============================
    ' 2. 扫描器内是: 注释 + 右括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getRightParenthesisToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRightParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非右括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRightParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRightParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非右括号
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRightParenthesisOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的目标元素的偏移量
Private Sub test_getNextTargetElemOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: union，搜索目标是 union
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTargetElemOffset(scanner, SqlTokenType.KEY_UNION)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + union，搜索目标是 union
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTargetElemOffset(scanner, SqlTokenType.KEY_UNION)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非 union，搜索目标是 union
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTargetElemOffset(scanner, SqlTokenType.KEY_UNION)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释，搜索目标是 union
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTargetElemOffset(scanner, SqlTokenType.KEY_UNION)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非 union，搜索目标是 union
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTargetElemOffset(scanner, SqlTokenType.KEY_UNION)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的筛选行为关键字的偏移量
Private Sub test_getNextSelectStartActionSqlKeyOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: distinct，搜索目标是 distinct
    ' ==============================
    Set scanner = getObjArrayRefScanner(getDistinctToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextSelectStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0


    ' ==============================
    ' 2. 扫描器内是: 注释 + distinct，搜索目标是 distinct
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getDistinctToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextSelectStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非 distinct，搜索目标是 distinct
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextSelectStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释，搜索目标是 distinct
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextSelectStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非 distinct，搜索目标是 distinct
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextSelectStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的不是sql各部分的起始关键字的偏移量
Private Sub test_getNextNonSectionStartSqlKeyOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: STR_NAME，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner(getStrNameToken("x1"))

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSectionStartSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + STR_NAME，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSectionStartSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非 STR_NAME，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSectionStartSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSectionStartSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非 STR_NAME ，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSectionStartSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近运算符的偏移量
Private Sub test_getNextOperatorOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: 运算符，搜索目标是 运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner(getLeConditionOperator)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + 运算符，搜索目标是 运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getLeConditionOperator _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非 运算符，搜索目标是 运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释，搜索目标是 运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非 运算符 ，搜索目标是 运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的算数运算符的偏移量
Private Sub test_getNextComputeOperatorOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: 算数运算符，搜索目标是 算数运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner(getPlusToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextComputeOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + 算数运算符，搜索目标是 算数运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getPlusToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextComputeOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非 算数运算符，搜索目标是 算数运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextComputeOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释，搜索目标是 算数运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextComputeOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非 算数运算符 ，搜索目标是 算数运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextComputeOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的条件运算符的偏移量 (为了兼容条件运算符前的 Not 运算符，这里也检查 Not)
Private Sub test_getNextConditionOperatorOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: 条件运算符，搜索目标是 条件运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner(getLeConditionOperator)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextConditionOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + 条件运算符，搜索目标是 条件运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getLeConditionOperator _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextConditionOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非 条件运算符，搜索目标是 条件运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextConditionOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释，搜索目标是 条件运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextConditionOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非 条件运算符 ，搜索目标是 条件运算符
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextConditionOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 6. 扫描器内是: Not ，搜索目标是 Not
    ' ==============================
    Set scanner = getObjArrayRefScanner(getNotToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextConditionOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 7. 扫描器内是: 注释 + Not，搜索目标是 Not
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getNotToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextConditionOperatorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的不是使匹配筛选项操作停止的sql关键字的偏移量
Private Sub test_getNextNonSelectItemStopSqlKeyOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: STR_NAME，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner(getStrNameToken("x1"))

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSelectItemStopSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + STR_NAME，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSelectItemStopSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. (找不到)扫描器中的是: 注释 + 非 STR_NAME，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSelectItemStopSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. (找不到)扫描器中的是: 2 个注释，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSelectItemStopSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 非 STR_NAME ，搜索目标是 STR_NAME
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextNonSelectItemStopSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的表定义的偏移量
Private Sub test_getNextTableFactorOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: STR_NAME，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner(getStrNameToken("x1"))

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + STR_NAME，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. 扫描器内是: select，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner(getSelectToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. 扫描器内是: 注释 + select，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getSelectToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. 扫描器内是: with，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner(getWithToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 6. 扫描器内是: 注释 + with，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getWithToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 7. 扫描器内是: 左括号，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner(getLeftParenthesisToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 8. 扫描器内是: 注释 + 左括号，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getLeftParenthesisToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 9. (找不到)扫描器中的是: 注释 + 非 表定义起始关键字，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 10. (找不到)扫描器中的是: 2 个注释，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 11. (找不到)扫描器中的是: 非 表定义起始关键字 ，搜索目标是 表定义
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextTableFactorOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的index_hint起始关键字的偏移量
Private Sub test_getNextIndexHintStartKeyOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器的下一个元素是: use
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUseToken _
    )
    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器的下一个元素是: ignore
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. 扫描器的下一个元素是: force
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getForceToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. 扫描器中的是: 注释 + use
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUseToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. 扫描器中的是: 注释 + ignore
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 6. 扫描器中的是: 注释 + force
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getForceToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 7. (找不到)扫描器中的是: 注释 + 非 use/ignore/force 的元素
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 8. (找不到)扫描器中的是: 2 个注释
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 9. (找不到)扫描器中的是: 非 use/ignore/force 的元素
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextIndexHintStartKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的with表定义的偏移量
Private Sub test_getNextWithTableOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: STR_NAME，搜索目标是 with表定义起始关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getStrNameToken("x1"))

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextWithTableOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + STR_NAME，搜索目标是 with表定义起始关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextWithTableOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. 扫描器内是: STR_FUNC，搜索目标是 with表定义起始关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(createFuncNameToken("max"))

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextWithTableOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. 扫描器内是: 注释 + STR_FUNC，搜索目标是 with表定义起始关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createFuncNameToken("max") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextWithTableOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 注释 + 非 with表定义起始关键字，搜索目标是 with表定义起始关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextWithTableOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 6. (找不到)扫描器中的是: 2 个注释，搜索目标是 with表定义起始关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextWithTableOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 7. (找不到)扫描器中的是: 非 表定义起始关键字 ，搜索目标是 with表定义起始关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextWithTableOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的update行为关键字的偏移量
Private Sub test_getNextUpdateStartActionSqlKeyOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: LOW_PRIORITY，搜索目标是 update行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getLowPriorityToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextUpdateStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + LOW_PRIORITY，搜索目标是 update行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getLowPriorityToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextUpdateStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. 扫描器内是: IGNORE，搜索目标是 update行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getIgnoreToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextUpdateStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. 扫描器内是: 注释 + IGNORE，搜索目标是 update行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextUpdateStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. (找不到)扫描器中的是: 注释 + 非 update行为关键字，搜索目标是 update行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextUpdateStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 6. (找不到)扫描器中的是: 2 个注释，搜索目标是 update行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextUpdateStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 7. (找不到)扫描器中的是: 非 update行为关键字 ，搜索目标是 update行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextUpdateStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的delete行为关键字的偏移量
Private Sub test_getNextDeleteStartActionSqlKeyOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: LOW_PRIORITY，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getLowPriorityToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + LOW_PRIORITY，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getLowPriorityToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. 扫描器内是: IGNORE，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getIgnoreToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. 扫描器内是: 注释 + IGNORE，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. 扫描器内是: QUICK，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getQuickToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 6. 扫描器内是: 注释 + QUICK，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getQuickToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 7. (找不到)扫描器中的是: 注释 + 非 delete行为关键字，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 8. (找不到)扫描器中的是: 2 个注释，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 9. (找不到)扫描器中的是: 非 delete行为关键字 ，搜索目标是 delete行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextDeleteStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个最近的insert行为关键字的偏移量
Private Sub test_getNextInsertStartActionSqlKeyOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: LOW_PRIORITY，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getLowPriorityToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + LOW_PRIORITY，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getLowPriorityToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. 扫描器内是: IGNORE，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getIgnoreToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. 扫描器内是: 注释 + IGNORE，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 5. 扫描器内是: DELAYED，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getDelayedToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 6. 扫描器内是: 注释 + DELAYED，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getDelayedToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 7. 扫描器内是: HIGH_PRIORITY，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner(getHighPriorityToken)

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 8. 扫描器内是: 注释 + HIGH_PRIORITY，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getHighPriorityToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 9. (找不到)扫描器中的是: 注释 + 非 insert行为关键字，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        getIgnoreToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 10. (找不到)扫描器中的是: 2 个注释，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 11. (找不到)扫描器中的是: 非 insert行为关键字 ，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextInsertStartActionSqlKeyOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub

' 测试: 获取扫描器到下一个rowAlias的偏移量
Private Sub test_getNextRowAliasOffset()
    Dim scanner As ObjArrayRefScanner
    Dim offset As Integer

    ' ==============================
    ' 1. 扫描器内是: STR_NAME，搜索目标是 rowAlias
    ' ==============================
    Set scanner = getObjArrayRefScanner(getStrNameToken("x1"))

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRowAliasOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 2. 扫描器内是: 注释 + STR_NAME，搜索目标是 rowAlias
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getStrNameToken("x1") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRowAliasOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 3. 扫描器内是: STR_FUNC，搜索目标是 rowAlias
    ' ==============================
    Set scanner = getObjArrayRefScanner(createFuncNameToken("xx"))

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRowAliasOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 1
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 4. 扫描器内是: 注释 + STR_FUNC，搜索目标是 rowAlias
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createFuncNameToken("xx") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRowAliasOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 2
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 9. (找不到)扫描器中的是: 注释 + 非 insert行为关键字，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        getUnionToken, _
        createFuncNameToken("xx") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRowAliasOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 10. (找不到)扫描器中的是: 2 个注释，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        createShareLineCommentToken("--c1"), _
        createShareLineCommentToken("--c2") _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRowAliasOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

    ' ==============================
    ' 11. (找不到)扫描器中的是: 非 insert行为关键字 ，搜索目标是 insert行为关键字
    ' ==============================
    Set scanner = getObjArrayRefScanner( _
        getUnionToken _
    )

    ' 1. 执行测试方法
    Debug.Assert scanner.ActiveIndex = 0
    offset = SqlFormatterHelper.getNextRowAliasOffset(scanner)

    ' 2. 检查结果
    Debug.Assert offset = 0
    Debug.Assert scanner.ActiveIndex = 0

End Sub